#include "floodfill.h"
#include <QDebug>
#include <QStack>
static inline bool fillPoint_Gray( QImage &image, QPoint p, uchar val, uchar newVal, QStack<QPoint> &stack)
{
    int x = p.rx();
    int y = p.ry();
    uchar *line = image.scanLine(y);
    if( line[x] != val )
    {
        return false;
    }
    line[x] = newVal;
    if( y > 0 )
    {
        uchar *last = image.scanLine(y - 1);
        if( last[x] == val )
        {
            stack.push(QPoint(x, y - 1));
        }
    }
    if( y < image.height() - 1 )
    {
        uchar *next = image.scanLine(y + 1);
        if( next[x] == val )
        {
            stack.push(QPoint(x, y + 1));
        }
    }
    return true;
}

bool floodFill_Gray(QImage &image, QPoint seedPoint, uchar newVal )
{
    if(image.format() != QImage::Format_Indexed8)
    {
        return false;
    }
    int width = image.width();
    int height = image.height();
    int x = seedPoint.rx();
    int y = seedPoint.ry();
    if(x < 0 || x >= width || y < 0 || y >= height)
    {
        return false;
    }
    int value = image.scanLine(y)[x];
    QStack<QPoint> stack;
    stack.push(seedPoint);

    //int temp = 10;
    while(!stack.isEmpty())
    {
        QPoint p = stack.pop();
        bool ret = fillPoint_Gray(image, p, value, newVal, stack);
        bool ret2 = ret;
        y = p.ry();
        x = p.rx();
        x--;
        while(x >= 0 && ret)
        {
            ret = fillPoint_Gray(image, QPoint(x, y), value, newVal, stack);
            x--;
        }

        x = p.rx();
        x ++;
        while(x < width && ret2)
        {
            ret2 = fillPoint_Gray(image, QPoint(x, y), value, newVal, stack);
            x++;
        }
        //image.save(QString("C:\\Users\\Ivan\\Documents\\floodFill\\%1.png").arg(temp));
        //temp ++;
    }
    return true;
}


static inline bool fillPoint_Gray( QImage &image, QPoint p, uchar low, uchar high, uchar newVal, QStack<QPoint> &stack)
{
    int x = p.rx();
    int y = p.ry();
    uchar *line = image.scanLine(y);
    if( line[x] < low || line[x] > high )
    {
        return false;
    }
    line[x] = newVal;
    if( y > 0 )
    {
        uchar *last = image.scanLine(y - 1);
        if( last[x] >= low && last[x] <= high )
        {
            stack.push(QPoint(x, y - 1));
        }
    }
    if( y < image.height() - 1 )
    {
        uchar *next = image.scanLine(y + 1);
        if( next[x] >= low && next[x] <= high )
        {
            stack.push(QPoint(x, y + 1));
        }
    }
    return true;
}

bool floodFill_Gray(QImage &image, QPoint seedPoint, int low, int high, uchar newVal )
{
    if(image.format() != QImage::Format_Indexed8)
    {
        return false;
    }
    low = qBound(0, low, 255);
    high = qBound(0, high, 255);
    if(low > high)
    {
        return false;
    }

    QStack<QPoint> stack;
    stack.push(seedPoint);

    int width = image.width();
    while(!stack.isEmpty())
    {
        QPoint p = stack.pop();
        bool ret = fillPoint_Gray(image, p, low, high, newVal, stack);
        bool ret2 = ret;
        int y = p.ry();
        int x = p.rx();
        x--;
        while(x >= 0 && ret)
        {
            ret = fillPoint_Gray(image, QPoint(x, y), low, high, newVal, stack);
            x--;
        }

        x = p.rx();
        x ++;
        while(x < width && ret2)
        {
            ret2 = fillPoint_Gray(image, QPoint(x, y), low, high, newVal, stack);
            x++;
        }
    }
    return true;
}


static inline bool fillPoint_RGB32( QImage &image, QPoint p, QRgb val, QRgb newVal, QStack<QPoint> &stack)
{
    int x = p.rx();
    int y = p.ry();
    QRgb *line = (QRgb*)image.scanLine(y);
    if( line[x] != val )
    {
        return false;
    }
    line[x] = newVal;
    if( y > 0 )
    {
        QRgb *last = (QRgb*)image.scanLine(y - 1);
        if( last[x] == val )
        {
            stack.push(QPoint(x, y - 1));
        }
    }
    if( y < image.height() - 1 )
    {
        QRgb *next = (QRgb*)image.scanLine(y + 1);
        if( next[x] == val )
        {
            stack.push(QPoint(x, y + 1));
        }
    }
    return true;
}

bool floodFill_RGB32(QImage &image, QPoint seedPoint, QRgb newVal )
{
    qDebug() << image.format();
    if(image.format() != QImage::Format_RGBA8888 && image.format() != QImage::Format_ARGB32 )
    {
        return false;
    }
    int width = image.width();
    int height = image.height();
    int x = seedPoint.rx();
    int y = seedPoint.ry();
    if(x < 0 || x >= width || y < 0 || y >= height)
    {
        return false;
    }
    QRgb value = image.pixel(x, y);
    QStack<QPoint> stack;
    stack.push(seedPoint);

    //int temp = 10;
    while(!stack.isEmpty())
    {
        QPoint p = stack.pop();
        bool ret = fillPoint_RGB32(image, p, value, newVal, stack);
        bool ret2 = ret;
        y = p.ry();
        x = p.rx();
        x--;
        while(x >= 0 && ret)
        {
            ret = fillPoint_RGB32(image, QPoint(x, y), value, newVal, stack);
            x--;
        }

        x = p.rx();
        x ++;
        while(x < width && ret2)
        {
            ret2 = fillPoint_RGB32(image, QPoint(x, y), value, newVal, stack);
            x++;
        }
        //image.save(QString("C:\\Users\\Ivan\\Documents\\floodFill\\%1.png").arg(temp));
        //temp ++;
    }
    return true;
}